package agenti.analisi;

import gui.AnalisiStatistica.TipoAnalisi;
import gui.AnalisiStatistica.TipoRaggruppamento;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;

import componenti.statistica.Esponenziale;
import componenti.statistica.GeneratoreCasuale;
import componenti.statistica.LeggeDistribuzione;

@SuppressWarnings("serial")
public class AgenteTempiSoggiorno extends Agent {

	List<Vector<Double>> lottiRepliche;
	Vector<double[]> medieIncrementali;
	private double[] tempiSoggiorno;
	private int elementiTotali;
	private TipoRaggruppamento tipoGruppo;
	private TipoAnalisi tipoAnalisi;
	private int transitorio;
	private int passo;
	private int numeroLottiRepliche;
	private double mediaPuntuale;
	private double[] mediaIntervallare;
	LeggeDistribuzione leggeProduttore;
	LeggeDistribuzione leggeConsumatore;

	@Override
	protected void setup() {
		lottiRepliche = new LinkedList<Vector<Double>>();
		mediaIntervallare = new double[2];
		Object[] parametri = getArguments();
		elementiTotali = (Integer) parametri[0];
		leggeProduttore = (LeggeDistribuzione) parametri[1];
		leggeConsumatore = (LeggeDistribuzione) parametri[2];
		tempiSoggiorno = generaTempiSoggiornoBuffer();
		tipoGruppo = (TipoRaggruppamento) parametri[3];
		tipoAnalisi = (TipoAnalisi) parametri[4];
		transitorio = (Integer) parametri[5];
		passo = (Integer) parametri[6];
		numeroLottiRepliche = (Integer) parametri[7];
		switch (tipoGruppo) {
		case LOTTI:
			addBehaviour(new LottiBehaviour());
			break;
		case REPLICHE:
			addBehaviour(new ReplicheBehaviour());
			break;

		default:
			break;
		}
	}

	@Override
	public String toString() {
		return "AgenteTempiSoggiorno [lottiRepliche=" + lottiRepliche
				+ ", medieIncrementali=" + medieIncrementali
				+ ", tempiSoggiorno=" + Arrays.toString(tempiSoggiorno)
				+ ", elementiTotali=" + elementiTotali + ", tipoGruppo="
				+ tipoGruppo + ", tipoAnalisi=" + tipoAnalisi
				+ ", transitorio_distanza=" + transitorio + ", passo=" + passo
				+ ", numeroLottiRepliche=" + numeroLottiRepliche
				+ ", leggeProduttore=" + leggeProduttore
				+ ", leggeConsumatore=" + leggeConsumatore + "]";
	}

	private double[] generaTempiSoggiornoBuffer() {
		// Genero numeri casuali Interarrivi
		Random prod = new Random((int) (Math.random() * 100));
		Random cons = new Random((int) (Math.random() * 100));
		double[] casualInterarrivo = new double[elementiTotali];
		for (int i = 0; i < casualInterarrivo.length; i++) {
			casualInterarrivo[i] = prod.nextDouble();
		}
		// Genero i numeri casuali per i tempi di servizio
		double[] casualServizio = new double[elementiTotali];
		for (int i = 0; i < casualServizio.length; i++) {
			casualServizio[i] = cons.nextDouble();
		}

		double[] tempiInterarrivo = GeneratoreCasuale.getSimulation(
				leggeProduttore, casualInterarrivo);

		double[] istantiArrivo = GeneratoreCasuale
				.getArriviDaInterarrivi(tempiInterarrivo);

		double[] tempiServizio = GeneratoreCasuale.getSimulation(
				leggeConsumatore, casualServizio);

		double[] istantiPartenza = GeneratoreCasuale.getIstantiPartenza(
				istantiArrivo, tempiServizio);

		double[] tempiSoggiornoSistema = GeneratoreCasuale
				.getTempiSoggiornoSistema(istantiArrivo, istantiPartenza);

		// System.out.println("TempiInterarrivo="
		// + Arrays.toString(tempiInterarrivo));
		// System.out.println("IstantiArrivo=" +
		// Arrays.toString(istantiArrivo));
		// System.out.println("TempiServizio=" +
		// Arrays.toString(tempiServizio));
		// System.out.println("IstanztiPartenza="
		// + Arrays.toString(istantiPartenza));
		// System.out.println("TempiSOggiornoSIstema="
		// + Arrays.toString(tempiSoggiornoSistema));
		// System.out.println("TempiSoggiornoBuffer="
		// + Arrays.toString(GeneratoreCasuale.getTempiSoggiornoBuffer(
		// tempiSoggiornoSistema, tempiServizio)));
		//
		// System.out.println("Tempo medio di interarrivo="
		// + GeneratoreCasuale.getMedia(tempiInterarrivo));
		// System.out.println("Tempo medio di servizio="
		// + GeneratoreCasuale.getMedia(tempiServizio));
		//
		//
		// System.out.println("Tempo medio di soggiorno="
		// + GeneratoreCasuale.getMedia(GeneratoreCasuale
		// .getTempiSoggiornoBuffer(tempiSoggiornoSistema,
		// tempiServizio)));

		return GeneratoreCasuale.getTempiSoggiornoBuffer(tempiSoggiornoSistema,
				tempiServizio);

	}

	private class LottiBehaviour extends Behaviour {

		@Override
		public void action() {
			int dimLotto = (elementiTotali - transitorio)
					/ (numeroLottiRepliche);
			for (int i = 0; i < numeroLottiRepliche; i++) {
				Vector<Double> lotto = new Vector<Double>();
				for (int j = 0; j < dimLotto; j = j + passo) {
					lotto.add(tempiSoggiorno[j + (i * dimLotto)]);
				}
				lottiRepliche.add(lotto);
			}
		}

		@Override
		public boolean done() {
			switch (tipoAnalisi) {
			case MEDIA:
				myAgent.addBehaviour(new MediaBehaviour());
				break;
			case DISTRIBUZIONE:
				myAgent.addBehaviour(new DistribuzioneBehaviour());
				break;
			case MEDIA_INCREMENTALE:
				myAgent.addBehaviour(new MediaIncrementale());
				break;
			default:
				break;
			}
			return true;
		}

	}

	private class ReplicheBehaviour extends Behaviour {

		@Override
		public void action() {
			Vector<Double> p = new Vector<Double>();
			for (int j = transitorio; j < tempiSoggiorno.length; j = j + passo) {
				p.add(tempiSoggiorno[j]);
			}
			lottiRepliche.add(p);
			for (int k = 0; k < numeroLottiRepliche - 1; k++) {
				double[] generazione = generaTempiSoggiornoBuffer();
				Vector<Double> elem = new Vector<Double>();
				for (int j = transitorio; j < generazione.length; j = j + passo) {
					elem.add(generazione[j]);
				}
				lottiRepliche.add(elem);
			}
		}

		@Override
		public boolean done() {
			switch (tipoAnalisi) {
			case MEDIA:
				myAgent.addBehaviour(new MediaBehaviour());
				break;
			case DISTRIBUZIONE:
				myAgent.addBehaviour(new DistribuzioneBehaviour());
				break;
			case MEDIA_INCREMENTALE:
				myAgent.addBehaviour(new MediaIncrementale());
				break;
			default:
				break;
			}
			return true;
		}

	}

	private class MediaBehaviour extends Behaviour {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		@Override
		public void action() {
			double[] medieLotti = new double[lottiRepliche.size()];
			int i = 0;
			for (Vector<Double> lotto : lottiRepliche) {
				double somma = 0;
				for (Double osservazione : lotto) {
					somma += osservazione / lotto.size();
				}
				medieLotti[i] = somma;
				// lotto.size();
				i++;

			}
			double media = 0;
			for (int j = 0; j < medieLotti.length; j++) {
				media += (medieLotti[j] / medieLotti.length);
			}
			costruisciStimaIntervallare(medieLotti);
			new GrandeMediaDesigner().design(medieLotti);
		}

		private void costruisciStimaIntervallare(double[] medieLotti) {
			double somma = 0;
			for (int i = 0; i < medieLotti.length; i++) {
				somma += medieLotti[i];
			}
			mediaPuntuale = somma / medieLotti.length;
			double varianzaCampionaria = 0;
			for (int i = 0; i < medieLotti.length; i++) {
				varianzaCampionaria += (medieLotti[i] - mediaPuntuale)
						* (medieLotti[i] - mediaPuntuale);
			}
			varianzaCampionaria = varianzaCampionaria / (medieLotti.length - 1);
			double min = mediaPuntuale
					- (1.72913279247219 * Math.sqrt(varianzaCampionaria) / Math
							.sqrt(medieLotti.length));
			double max = mediaPuntuale
					+ (1.72913279247219 * Math.sqrt(varianzaCampionaria) / Math
							.sqrt(medieLotti.length));
			mediaIntervallare[0] = min;
			mediaIntervallare[1] = max;

			// System.out.println("MEDIA PUNTUALE"+mediaPuntuale);
			// System.out.println("VARIANZA CAMPIONARIA"+varianzaCampionaria);
			// System.out.println("LOWER BOUND"+mediaIntervallare[0]);
			// System.out.println("UPPER BOUND"+mediaIntervallare[1]);
		}

		@Override
		public boolean done() {
			myAgent.doDelete();
			return true;
		}

	}

	private class MediaIncrementale extends Behaviour {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		@Override
		public void action() {
			int dimensioneLotto = 100;
			int numPassi = lottiRepliche.get(0).size() / dimensioneLotto;
			medieIncrementali = new Vector<double[]>();
			int x = 1;
			// System.out.println("Size di LottiRepliche" +
			// lottiRepliche.size());
			for (Vector<Double> lottoRun : lottiRepliche) {
				double[] medieEnnesimoLotto = new double[numPassi];
				for (int j = 1; j <= numPassi; j++) {
					for (int k = 0; k < (j) * dimensioneLotto; k++) {
						medieEnnesimoLotto[j - 1] += lottoRun.get(k);
					}
					medieEnnesimoLotto[j - 1] = medieEnnesimoLotto[j - 1]
							/ ((j) * dimensioneLotto);
					// System.out.println("Medie Incrementali per "
					// + (dimensioneLotto * j) + " elementi del run " + x
					// + Arrays.toString(medieEnnesimoLotto));
				}
				medieIncrementali.add(medieEnnesimoLotto);
				x++;
			}
			new MedieIncrementaliDesigner().design();
		}

		@Override
		public boolean done() {
			myAgent.doDelete();
			return true;
		}

	}

	private class MedieIncrementaliDesigner extends JFrame {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void design() {
			XYDataset dataset;
			JFreeChart jfc;
			dataset = createDataset(medieIncrementali);
			jfc = createChart(dataset);
			ChartPanel chartPanel = new ChartPanel(jfc);
			chartPanel.setPreferredSize(new Dimension(500, 270));
			setContentPane(chartPanel);
			pack();
			RefineryUtilities.centerFrameOnScreen(this);
			setVisible(true);
		}

		private XYDataset createDataset(Vector<double[]> medieIncrementali) {
			XYSeriesCollection dataset = new XYSeriesCollection();
			int i = 0;
			// double[] medieRun = medieIncrementali.get(0);
			for (double[] medieRun : medieIncrementali) {
				XYSeries s1 = new XYSeries("Run " + i);
				int passi = 0;
				for (int j = 0; j < medieRun.length; j++) {
					s1.add(passi, medieRun[j]);
					passi += 100;
				}
				i++;
				dataset.addSeries(s1);
			}
			return dataset;
		}

		@SuppressWarnings("deprecation")
		private JFreeChart createChart(XYDataset dataset) {
			// create the chart...
			JFreeChart chart = ChartFactory.createXYLineChart(
					"Processo stocastico Grande Media", // chart title
					"Variabili Aleatorie Media per n campioni", // x axis label
					"Media", // y axis label
					dataset, // data
					PlotOrientation.VERTICAL, true, // include legend
					true, // tooltips
					false // urls
					);
			// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
			chart.setBackgroundPaint(Color.white);
			// get a reference to the plot for further customisation...
			XYPlot plot = (XYPlot) chart.getPlot();
			plot.setBackgroundPaint(Color.lightGray);
			plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
			plot.setDomainGridlinePaint(Color.white);
			plot.setRangeGridlinePaint(Color.white);
			XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot
					.getRenderer();
			renderer.setShapesVisible(true);
			renderer.setShapesFilled(true);
			// change the auto tick unit selection to integer units only...
			NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
			rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
			// OPTIONAL CUSTOMISATION COMPLETED.
			return chart;
		}

	}

	private class DistribuzioneBehaviour extends Behaviour {

		@Override
		public void action() {
			medieIncrementali = new Vector<double[]>();
			int x = 1;
			// int intervalli = (int) Math.sqrt((elementiTotali - transitorio)
			// / numeroLottiRepliche);
			int intervalli = 20;
			System.out.println("Intervalli: " + intervalli);
			for (Vector<Double> lottoRun : lottiRepliche) {
				// mettere variabile
				double[] valoriEnnesimoLotto = new double[intervalli];
				for (int i = 0; i < valoriEnnesimoLotto.length; i++) {
					valoriEnnesimoLotto[i] = 0;
				}
				double media = 0;
				int index = 0;
				// rimuovo i tempi di attesa pari a zero per fare in modo di
				// avere solo la distribuzione dei tempi di attesa di quelli che
				// aspettano
				Iterator<Double> it = lottoRun.iterator();
				while (it.hasNext()) {
					Double double1 = (Double) it.next();
					if (double1 < 0.001) {
						it.remove();
					}
				}
				// calcolo la media del lotto per stimare il tazzo
				// dell'esponenziale
				System.out.println("Size Lotto Pulito: " + lottoRun.size());
				System.out.println("Elementi del Lotto: " + lottoRun);
				for (Double d : lottoRun) {
					media += (d / lottoRun.size());
				}
				double max = 0;
				double min = Double.MAX_VALUE;
				for (Double d : lottoRun) {
					if (d > max)
						max = d;
					if (d < min)
						min = d;
				}

				System.out.println("Massimo: " + max);
				System.out.println("Minimo: " + min);
				double ampiezza = (max - min) / intervalli;

				System.out.println("Ampiezza: " + ampiezza);
				Esponenziale exp = new Esponenziale(1 / media);
				for (int i = 1; i <= intervalli; i++) {
					// double tmp = 1 - ((1 / (double) ampiezza) * i);
					// double limite = exp.getRealization(tmp);
					// double tmp1 = 1 - ((1 / (double) ampiezza) * (i - 1));
					// double limite2 = exp.getRealization(tmp1);
					double limite = min + (ampiezza * i);
					double limite2;
					if (i == 1) {
						limite2 = ampiezza;
					} else {
						limite2 = min + (ampiezza * (i - 1));
					}
					System.out.println("Limite Inf: " + limite2);
					System.out.println("Limite Sup: " + limite);
					for (Double d : lottoRun) {
						if (d < limite && d >= limite2) {
							valoriEnnesimoLotto[i - 1]++;
						}

						index++;
						if (index == valoriEnnesimoLotto.length - 1) {
							break;
						}
					}

				}
				int totale = 0;
				int diversiZero = 0;
				for (int j = 0; j < valoriEnnesimoLotto.length; j++) {
					totale += valoriEnnesimoLotto[j];
					if (valoriEnnesimoLotto[j] != 0) {
						diversiZero++;
					}
				}
				System.out.println("Totale" + totale);
				// for (int j = 0; j < valoriEnnesimoLotto.length; j++) {
				// valoriEnnesimoLotto[j] = valoriEnnesimoLotto[j] / totale;
				// }
				System.out.println("Distribuz Prob"
						+ Arrays.toString(valoriEnnesimoLotto));
				for (int i = 0; i < valoriEnnesimoLotto.length; i++) {
					valoriEnnesimoLotto[i] /= lottoRun.size();
				}
				
				double[] valoriEnnesimoLottoPrimo = new double[diversiZero];
				int pos = 0;
				for (int i = 0; i < valoriEnnesimoLotto.length; i++) {
					if (valoriEnnesimoLotto[i] != 0) {
						valoriEnnesimoLottoPrimo[pos] = valoriEnnesimoLotto[i];
						pos++;
					}
				}
				
				medieIncrementali.add(valoriEnnesimoLottoPrimo);
				System.out.println(Arrays.toString(valoriEnnesimoLottoPrimo));
				x++;
			}
			new DistribuzioneDesigner().design();
		}

		@Override
		public boolean done() {
			doDelete();
			return true;
		}

	}

	private class DistribuzioneDesigner extends JFrame {

		private static final long serialVersionUID = 1L;

		public void design() {
			DefaultCategoryDataset dataset;
			JFreeChart jfc;
			dataset = createDataset(medieIncrementali);
			jfc = createChart(dataset);
			ChartPanel chartPanel = new ChartPanel(jfc);
			chartPanel.setPreferredSize(new Dimension(500, 270));
			setContentPane(chartPanel);
			pack();
			RefineryUtilities.centerFrameOnScreen(this);
			System.out.println(dataset);
			setVisible(true);
		}

		private DefaultCategoryDataset createDataset(
				Vector<double[]> medieIncrementali) {
			DefaultCategoryDataset dataset = new DefaultCategoryDataset();
			int x = 1;
			System.out.println("Size dei vettori="
					+ medieIncrementali.get(0).length);
			for (double[] medieRun : medieIncrementali) {
				// System.out.println("Vettore da mettere nel diagramma"
				// + Arrays.toString(medieRun));
				for (int i = 0; i < medieRun.length; i++) {
					dataset.addValue(medieRun[i], "" + "Lotto " + x,
							"Tempo di Attesa " + i);
				}
				x++;
			}
			return dataset;
		}

		private JFreeChart createChart(DefaultCategoryDataset dataset) {
			// create the chart...
			JFreeChart chart = ChartFactory.createBarChart("Bar Chart Demo", // chart
					// title
					"Category", // domain axis label
					"Value", // range axis label
					dataset, // data
					PlotOrientation.VERTICAL, // orientation
					true, // include legend
					true, // tooltips?
					false // URLs?
					);
			// // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
			// chart.setBackgroundPaint(Color.white);
			// // get a reference to the plot for further customisation...
			// XYPlot plot = (XYPlot) chart.getPlot();
			// plot.setBackgroundPaint(Color.lightGray);
			// plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
			// plot.setDomainGridlinePaint(Color.white);
			// plot.setRangeGridlinePaint(Color.white);
			// XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot
			// .getRenderer();
			// renderer.setShapesVisible(true);
			// renderer.setShapesFilled(true);
			// // change the auto tick unit selection to integer units only...
			// NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
			// rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
			// // OPTIONAL CUSTOMISATION COMPLETED.
			return chart;
		}

	}

	public static void main(String[] args) {
		int[] casualInterarrivo = new int[12];
		for (int i = 0; i < casualInterarrivo.length; i++) {
			casualInterarrivo[i] = (int) (new Random().nextDouble() * 100);
		}
		for (int i = 0; i < 4; i++) {
			Vector<Integer> lotto = new Vector<Integer>();
			for (int j = 0; j < 3; j++) {
				lotto.add(casualInterarrivo[j + (i * 3)]);
			}
			// System.out.println(lotto.toString());
		}
	}

	private class GrandeMediaDesigner extends JFrame {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public void design(double[] medieLotti) {
			CategoryDataset dataset;
			JFreeChart jfc;
			dataset = createDataset(medieLotti);
			jfc = createChart(dataset);
			ChartPanel chartPanel = new ChartPanel(jfc);
			chartPanel.setPreferredSize(new Dimension(500, 270));
			JPanel panel = new JPanel(new GridBagLayout());
			panel.add(new JLabel("Media puntuale"), new GridBagConstraints(0,
					0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
					GridBagConstraints.BOTH, new Insets(10, 10, 5, 2), 0, 0));
			panel.add(new JLabel(mediaPuntuale + ""), new GridBagConstraints(1,
					0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
					GridBagConstraints.BOTH, new Insets(10, 10, 5, 2), 0, 0));
			panel.add(new JLabel("LOWER BOUND"), new GridBagConstraints(0, 2,
					1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
					GridBagConstraints.BOTH, new Insets(10, 10, 5, 2), 0, 0));
			panel.add(new JLabel(mediaIntervallare[0] + ""),
					new GridBagConstraints(1, 2, 1, 1, 1.0, 1.0,
							GridBagConstraints.CENTER, GridBagConstraints.BOTH,
							new Insets(10, 10, 5, 2), 0, 0));
			panel.add(new JLabel("UPPER BOUND"), new GridBagConstraints(0, 3,
					1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
					GridBagConstraints.BOTH, new Insets(10, 10, 5, 2), 0, 0));
			panel.add(new JLabel(mediaIntervallare[1] + ""),
					new GridBagConstraints(1, 3, 1, 1, 1.0, 1.0,
							GridBagConstraints.CENTER, GridBagConstraints.BOTH,
							new Insets(10, 10, 5, 2), 0, 0));
			GrandeMediaDesigner.this.add(chartPanel, BorderLayout.CENTER);
			GrandeMediaDesigner.this.add(panel, BorderLayout.EAST);
			// setContentPane(chartPanel);
			pack();
			RefineryUtilities.centerFrameOnScreen(this);
			setVisible(true);
		}

		private CategoryDataset createDataset(double[] medieLotti) {
			// System.out.println(Arrays.toString(medieLotti));
			DefaultCategoryDataset dataset = new DefaultCategoryDataset();
			for (int i = 0; i < medieLotti.length; i++) {
				dataset.addValue(medieLotti[i], "Lotti",
						((Integer) i).toString());
			}
			return dataset;
		}

		@SuppressWarnings("deprecation")
		private JFreeChart createChart(CategoryDataset dataset) {
			// create the chart...
			JFreeChart chart = ChartFactory.createLineChart(
					"Variabile Aleatoria Grande Media", // chart title
					"Numero Lotti ", // domain axis label
					"Media Lotti", // range axis label
					dataset, // data
					PlotOrientation.VERTICAL, // orientation
					false, // include legend
					true, // tooltips
					false // urls
					);
			chart.setBackgroundPaint(Color.white);
			CategoryPlot plot = (CategoryPlot) chart.getPlot();
			plot.setBackgroundPaint(Color.lightGray);
			plot.setRangeGridlinePaint(Color.white);
			// customise the range axis...
			NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
			rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
			// customise the renderer...
			LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot
					.getRenderer();
			renderer.setShapesVisible(true);
			renderer.setDrawOutlines(true);
			renderer.setUseFillPaint(true);
			renderer.setFillPaint(Color.white);
			return chart;
		}
	}

}
